{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7421cef5",
   "metadata": {},
   "source": [
    "### 初始化环境"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "18cdf54d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在jupyter notebook里env.render看不到窗口\n",
    "# 写一个helper类，用matplotlib刷新显示图像\n",
    "# 初始化传入env，调用helper的render即可\n",
    "from IPython import display # 导入display模块，用于在Jupyter Notebook中显示图像\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt # 导入matplotlib库，用于绘制图像\n",
    "%matplotlib inline\n",
    "\n",
    "class GymHelper:\n",
    "    def __init__(self, env, figsize = (3, 3)):\n",
    "        self.env = env # 初始化Gym环境\n",
    "        self.figsize = figsize # 初始化绘图窗口大小\n",
    "        \n",
    "        plt.figure(figsize = figsize) # 创建绘图窗口\n",
    "        plt.title(self.env.spec.id) # 标题设为环境名\n",
    "        self.img = plt.imshow(env.render()) # 在绘图窗口中显示初始图像\n",
    "    \n",
    "    def render(self, title = None):\n",
    "        image_data = self.env.render() # 获取当前环境图像渲染数据\n",
    "        \n",
    "        self.img.set_data(image_data) # 更新绘图窗口中的图像数据\n",
    "        display.display(plt.gcf()) # 刷新显示\n",
    "        display.clear_output(wait = True) # 有新图片时再清除绘图窗口原有图像\n",
    "        if title: # 如果有标题，就显示标题\n",
    "            plt.title(title)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5881877f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 导入gym库\n",
    "import gym\n",
    "\n",
    "# 创建CartPole环境，指定渲染模式为rgb_array，如果是在IDE中可以改为'human'\n",
    "env = gym.make('CartPole-v1', render_mode='rgb_array')\n",
    "# 重置环境\n",
    "env.reset()\n",
    "# 创建GymHelper\n",
    "gym_helper = GymHelper(env)\n",
    "\n",
    "# 循环N次\n",
    "for i in range(100):\n",
    "    gym_helper.render(title = str(i)) # 渲染环境\n",
    "    action = env.action_space.sample() # 从动作空间中随机选取一个动作\n",
    "    observation, reward, terminated, truncated, info = env.step(action) # 执行动作\n",
    "    if terminated or truncated: # 如果游戏结束，则结束循环\n",
    "        break\n",
    "\n",
    "# 游戏结束\n",
    "gym_helper.render(title = \"Finished\")\n",
    "# 关闭环境\n",
    "env.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a86c4be",
   "metadata": {},
   "source": [
    "环境介绍 https://www.gymlibrary.dev/environments/classic_control/cart_pole/"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "294a8fd4",
   "metadata": {},
   "source": [
    "### 1. DDQN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ce08e15f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入必要的库\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "import torch.nn.functional as F\n",
    "\n",
    "import numpy as np\n",
    "import sys\n",
    "import time\n",
    "import random\n",
    "import collections\n",
    "from tqdm import * # 用于显示进度条\n",
    "\n",
    "# 定义简单神经网络\n",
    "class Net(nn.Module):\n",
    "    def __init__(self, input_dim, output_dim):\n",
    "        super(Net, self).__init__()\n",
    "        self.input_dim = input_dim # 网络的输入维度\n",
    "        self.output_dim = output_dim # 网络的输出维度\n",
    "        \n",
    "        # 定义一个仅包含全连接层的网络，激活函数使用ReLU函数\n",
    "        self.fc = nn.Sequential(\n",
    "            nn.Linear(self.input_dim, 64),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(64, 128),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, self.output_dim)\n",
    "        )\n",
    "    \n",
    "    # 定义前向传播，输出动作Q值\n",
    "    def forward(self, state):\n",
    "        action = self.fc(state)\n",
    "        return action"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f7ebfe82",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 经验回放缓冲区\n",
    "class ReplayBuffer:\n",
    "    # 构造函数，max_size是缓冲区的最大容量\n",
    "    def __init__(self, max_size):\n",
    "        self.max_size = max_size\n",
    "        self.buffer = collections.deque(maxlen = self.max_size)  # 用collections的队列存储，先进先出\n",
    "\n",
    "    # 添加experience（五元组）到缓冲区\n",
    "    def add(self, state, action, reward, next_state, done):\n",
    "        experience = (state, action, reward, next_state, done)\n",
    "        self.buffer.append(experience)\n",
    "\n",
    "    # 从buffer中随机采样，数量为batch_size\n",
    "    def sample(self, batch_size):\n",
    "        batch = random.sample(self.buffer, batch_size)\n",
    "        state, action, reward, next_state, done = zip(*batch)\n",
    "        return state, action, reward, next_state, done\n",
    "    \n",
    "    # 返回缓冲区数据数量\n",
    "    def __len__(self):\n",
    "        return len(self.buffer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "23fb1098",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义DDQN代理类\n",
    "class Agent:\n",
    "    # 构造函数，参数包含环境，学习率，折扣因子，经验回放缓冲区大小，目标网络更新频率\n",
    "    def __init__(self, env, learning_rate=0.001, gamma=0.99, buffer_size=10000, T=10):\n",
    "        self.env = env\n",
    "        self.learning_rate = learning_rate\n",
    "        self.gamma = gamma\n",
    "        self.replay_buffer = ReplayBuffer(max_size=buffer_size)\n",
    "        self.T = T\n",
    "\n",
    "        # 判断可用的设备是 CPU 还是 GPU\n",
    "        self.device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "        # 定义Q网络和目标网络，模型结构是一样的\n",
    "        self.model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "        self.target_model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "\n",
    "        # 初始化时，令目标网络的参数就等于Q网络的参数\n",
    "        for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "            target_param.data.copy_(param)\n",
    "\n",
    "        # 定义Adam优化器\n",
    "        self.optimizer = torch.optim.Adam(self.model.parameters())\n",
    "        \n",
    "        # 记录模型更新的次数，用于决定何时更新目标模型\n",
    "        self.update_count = 0\n",
    "    \n",
    "    # 根据epsilon-greedy策略选择动作\n",
    "    def choose_action(self, state, epsilon=0.1):\n",
    "        if np.random.rand() < epsilon: # 以epsilon的概率随机选择一个动作\n",
    "            return np.random.randint(self.env.action_space.n)\n",
    "        else: # 否则选择模型认为最优的动作\n",
    "            state = torch.FloatTensor(np.array([state])).to(self.device)\n",
    "            action = self.model(state).argmax().item()\n",
    "            return action\n",
    "    \n",
    "    # 计算损失函数，参数batch为随机采样的一批数据\n",
    "    def compute_loss(self, batch):\n",
    "        # 取出数据，并将其转换为numpy数组\n",
    "        # 然后进一步转换为tensor，并将数据转移到指定计算资源设备上\n",
    "        states, actions, rewards, next_states, dones = batch\n",
    "        states = torch.FloatTensor(np.array(states)).to(self.device)\n",
    "        actions = torch.tensor(np.array(actions)).view(-1, 1).to(self.device)\n",
    "        rewards = torch.FloatTensor(np.array(rewards)).view(-1, 1).to(self.device)\n",
    "        next_states = torch.FloatTensor(np.array(next_states)).to(self.device)\n",
    "        dones = torch.FloatTensor(np.array(dones)).view(-1, 1).to(self.device)\n",
    "\n",
    "        # 计算当前Q值，即Q网络对当前状态动作样本对的Q值估计\n",
    "        curr_Q = self.model(states).gather(1, actions)\n",
    "        # 计算目标网络对下一状态的Q值估计,DDQN区别于DQN的点\n",
    "        next_model_Q = self.model(next_states)\n",
    "        next_target_Q = self.target_model(next_states)\n",
    "        # 选择下一状态中最大的Q值\n",
    "        max_next_Q = next_target_Q.gather(1, torch.max(next_model_Q, 1)[1].unsqueeze(1))\n",
    "        # 计算期望的Q值，若达到终止状态则直接是reward\n",
    "        expected_Q = rewards + (1 - dones) * self.gamma * max_next_Q\n",
    "        \n",
    "        # 计算当前Q值和期望Q值之间的均方误差，返回结果\n",
    "        loss = torch.mean(F.mse_loss(curr_Q, expected_Q))\n",
    "        return loss\n",
    "    \n",
    "    # 模型更新，参数为批次大小\n",
    "    def update(self, batch_size):\n",
    "        # 从经验回放缓冲区中随机采样\n",
    "        batch = self.replay_buffer.sample(batch_size)\n",
    "        # 计算这部分数据的损失\n",
    "        loss = self.compute_loss(batch)\n",
    "\n",
    "        # 梯度清零、反向传播、更新参数\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        self.optimizer.step()\n",
    "        \n",
    "        # 每隔一段时间，更新目标网络的参数\n",
    "        if self.update_count % self.T == 0:\n",
    "            for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "                target_param.data.copy_(param)\n",
    "        # 记录模型更新的次数\n",
    "        self.update_count += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "ca21b5c5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Episode 0: 10.0                        \n",
      "Episode 40: 75.0                                \n",
      "Episode 80: 212.0                               \n",
      "Episode 120: 321.0                               \n",
      "Episode 160: 122.0                               \n",
      "100%|██████████| 200/200 [01:20<00:00,  2.50it/s]\n"
     ]
    }
   ],
   "source": [
    "# 定义超参数\n",
    "max_episodes = 200 # 训练episode数\n",
    "max_steps = 500 # 每个回合的最大步数\n",
    "batch_size = 32 # 采样数\n",
    "\n",
    "# 创建DQN对象\n",
    "agent = Agent(env)\n",
    "# 定义保存每个回合奖励的列表\n",
    "episode_rewards = []\n",
    "\n",
    "# 开始循环，tqdm用于显示进度条并评估任务时间开销\n",
    "for episode in tqdm(range(max_episodes), file=sys.stdout):\n",
    "    # 重置环境并获取初始状态\n",
    "    state, _ = env.reset()\n",
    "    # 当前回合的奖励\n",
    "    episode_reward = 0\n",
    "\n",
    "    # 循环进行每一步操作\n",
    "    for step in range(max_steps):\n",
    "        # 根据当前状态选择动作\n",
    "        action = agent.choose_action(state)\n",
    "        # 执行动作，获取新的信息\n",
    "        next_state, reward, terminated, truncated, info = env.step(action)\n",
    "        # 判断是否达到终止状态\n",
    "        done = terminated or truncated\n",
    "        \n",
    "        # 将这个五元组加到缓冲区中\n",
    "        agent.replay_buffer.add(state, action, reward, next_state, done)\n",
    "        # 累计奖励\n",
    "        episode_reward += reward\n",
    "\n",
    "        # 如果经验回放缓冲区已经有足够数据，就更新网络参数\n",
    "        if len(agent.replay_buffer) > batch_size:\n",
    "            agent.update(batch_size)\n",
    "        \n",
    "        # 更新当前状态\n",
    "        state = next_state\n",
    "\n",
    "        if done:\n",
    "            break\n",
    "    # 记录当前回合奖励值\n",
    "    episode_rewards.append(episode_reward)\n",
    "    # 打印中间值\n",
    "    if episode % 40 == 0:\n",
    "        tqdm.write(\"Episode \" + str(episode) + \": \" + str(episode_reward))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c8a9e9b4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 使用Matplotlib绘制奖励值的曲线图\n",
    "plt.plot(episode_rewards)\n",
    "plt.title(\"reward\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "e26c5808",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 重置环境，开始新的一轮游戏\n",
    "observation, _ = env.reset()\n",
    "# 创建GymHelper对象来辅助显示\n",
    "gym_helper = GymHelper(env, figsize = (3, 3))\n",
    "\n",
    "# 开始游戏\n",
    "for i in range(500):\n",
    "    # 渲染环境，title为当前步骤数\n",
    "    gym_helper.render(title = str(i))\n",
    "    \n",
    "    # 通过Q网络找到当前状态下的最优动作\n",
    "    action = agent.choose_action(observation, 0)\n",
    "    # 执行action，获取新的信息\n",
    "    observation, reward, terminated, truncated, info = env.step(action)\n",
    "    \n",
    "    # 如果游戏结束，则结束当前循环\n",
    "    if terminated or truncated:\n",
    "        break\n",
    "\n",
    "# 游戏结束\n",
    "gym_helper.render(title = \"Finished\")\n",
    "# 关闭环境\n",
    "env.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d55b4c5",
   "metadata": {},
   "source": [
    "### 2. Dueling DQN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "09eef2b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Dueling_DQN网络\n",
    "class Net(nn.Module):\n",
    "    def __init__(self, input_dim, output_dim):\n",
    "        super(Net, self).__init__()\n",
    "        \n",
    "        self.input_dim = input_dim\n",
    "        self.output_dim = output_dim\n",
    "        # 定义一个仅包含全连接层的网络，激活函数使用ReLU函数\n",
    "        self.fc = nn.Sequential(\n",
    "            nn.Linear(self.input_dim, 64),\n",
    "            nn.ReLU(),\n",
    "        )\n",
    "        \n",
    "        self.advantage = nn.Sequential(\n",
    "            nn.Linear(64, 128),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, output_dim)\n",
    "        )\n",
    "        \n",
    "        self.value = nn.Sequential(\n",
    "            nn.Linear(64, 128),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 1)\n",
    "        )\n",
    "    \n",
    "    # 定义前向传播，输出动作Q值\n",
    "    def forward(self, x):\n",
    "        x = self.fc(x)\n",
    "        x = x.view(x.size(0), -1)\n",
    "        advantage = self.advantage(x)\n",
    "        value     = self.value(x)\n",
    "        action_prob = value + advantage - advantage.mean()\n",
    "        return action_prob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0a20ce17",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 经验回放缓冲区\n",
    "class ReplayBuffer:\n",
    "    # 构造函数，max_size是缓冲区的最大容量\n",
    "    def __init__(self, max_size):\n",
    "        self.max_size = max_size\n",
    "        self.buffer = collections.deque(maxlen = self.max_size)  # 用collections的队列存储，先进先出\n",
    "\n",
    "    # 添加experience（五元组）到缓冲区\n",
    "    def add(self, state, action, reward, next_state, done):\n",
    "        experience = (state, action, reward, next_state, done)\n",
    "        self.buffer.append(experience)\n",
    "\n",
    "    # 从buffer中随机采样，数量为batch_size\n",
    "    def sample(self, batch_size):\n",
    "        batch = random.sample(self.buffer, batch_size)\n",
    "        state, action, reward, next_state, done = zip(*batch)\n",
    "        return state, action, reward, next_state, done\n",
    "    \n",
    "    # 返回缓冲区数据数量\n",
    "    def __len__(self):\n",
    "        return len(self.buffer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "6bf02741",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义DQN类\n",
    "class Agent:\n",
    "    # 构造函数，参数包含环境，学习率，折扣因子，经验回放缓冲区大小，目标网络更新频率\n",
    "    def __init__(self, env, learning_rate=0.001, gamma=0.99, buffer_size=10000, T=10):\n",
    "        self.env = env\n",
    "        self.learning_rate = learning_rate\n",
    "        self.gamma = gamma\n",
    "        self.replay_buffer = ReplayBuffer(max_size=buffer_size)\n",
    "        self.T = T\n",
    "\n",
    "        # 判断可用的设备是 CPU 还是 GPU\n",
    "        self.device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "        # 定义Q网络和目标网络，模型结构是一样的\n",
    "        self.model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "        self.target_model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "\n",
    "        # 初始化时，令目标网络的参数就等于Q网络的参数\n",
    "        for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "            target_param.data.copy_(param)\n",
    "\n",
    "        # 定义Adam优化器\n",
    "        self.optimizer = torch.optim.Adam(self.model.parameters())\n",
    "        \n",
    "        # 记录模型更新的次数，用于决定何时更新目标模型\n",
    "        self.update_count = 0\n",
    "    \n",
    "    # 根据epsilon-greedy策略选择动作\n",
    "    def choose_action(self, state, epsilon=0.1):\n",
    "        if np.random.rand() < epsilon: # 以epsilon的概率随机选择一个动作\n",
    "            return np.random.randint(self.env.action_space.n)\n",
    "        else: # 否则选择模型认为最优的动作\n",
    "            state = torch.FloatTensor(np.array([state])).to(self.device)\n",
    "            action = self.model(state).argmax().item()\n",
    "            return action\n",
    "    \n",
    "    # 计算损失函数，参数batch为随机采样的一批数据\n",
    "    def compute_loss(self, batch):\n",
    "        # 取出数据，并将其转换为numpy数组\n",
    "        # 然后进一步转换为tensor，并将数据转移到指定计算资源设备上\n",
    "        states, actions, rewards, next_states, dones = batch\n",
    "        states = torch.FloatTensor(np.array(states)).to(self.device)\n",
    "        actions = torch.tensor(np.array(actions)).view(-1, 1).to(self.device)\n",
    "        rewards = torch.FloatTensor(np.array(rewards)).view(-1, 1).to(self.device)\n",
    "        next_states = torch.FloatTensor(np.array(next_states)).to(self.device)\n",
    "        dones = torch.FloatTensor(np.array(dones)).view(-1, 1).to(self.device)\n",
    "\n",
    "        # 计算当前Q值，即Q网络对当前状态动作样本对的Q值估计\n",
    "        curr_Q = self.model(states).gather(1, actions)\n",
    "        # 计算目标网络对下一状态的Q值估计\n",
    "        next_Q = self.target_model(next_states)\n",
    "        # 选择下一状态中最大的Q值\n",
    "        max_next_Q = torch.max(next_Q, 1)[0].view(-1, 1)\n",
    "        # 计算期望的Q值，若达到终止状态则直接是reward\n",
    "        expected_Q = rewards + (1 - dones) * self.gamma * max_next_Q\n",
    "        \n",
    "        # 计算当前Q值和期望Q值之间的均方误差，返回结果\n",
    "        loss = torch.mean(F.mse_loss(curr_Q, expected_Q))\n",
    "        return loss\n",
    "    \n",
    "    # 模型更新，参数为批次大小\n",
    "    def update(self, batch_size):\n",
    "        # 从经验回放缓冲区中随机采样\n",
    "        batch = self.replay_buffer.sample(batch_size)\n",
    "        # 计算这部分数据的损失\n",
    "        loss = self.compute_loss(batch)\n",
    "\n",
    "        # 梯度清零、反向传播、更新参数\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        self.optimizer.step()\n",
    "        \n",
    "        # 每隔一段时间，更新目标网络的参数\n",
    "        if self.update_count % self.T == 0:\n",
    "            for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "                target_param.data.copy_(param)\n",
    "        # 记录模型更新的次数\n",
    "        self.update_count += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "66c03c71",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Episode 0: 9.0                         \n",
      "Episode 40: 107.0                               \n",
      "Episode 80: 283.0                               \n",
      "Episode 120: 500.0                               \n",
      "Episode 160: 500.0                               \n",
      "100%|██████████| 200/200 [02:00<00:00,  1.66it/s]\n"
     ]
    }
   ],
   "source": [
    "# 定义超参数\n",
    "max_episodes = 200 # 训练episode数\n",
    "max_steps = 500 # 每个回合的最大步数\n",
    "batch_size = 32 # 采样数\n",
    "\n",
    "# 创建DQN对象\n",
    "agent = Agent(env)\n",
    "# 定义保存每个回合奖励的列表\n",
    "episode_rewards = []\n",
    "\n",
    "# 开始循环，tqdm用于显示进度条并评估任务时间开销\n",
    "for episode in tqdm(range(max_episodes), file=sys.stdout):\n",
    "    # 重置环境并获取初始状态\n",
    "    state, _ = env.reset()\n",
    "    # 当前回合的奖励\n",
    "    episode_reward = 0\n",
    "\n",
    "    # 循环进行每一步操作\n",
    "    for step in range(max_steps):\n",
    "        # 根据当前状态选择动作\n",
    "        action = agent.choose_action(state)\n",
    "        # 执行动作，获取新的信息\n",
    "        next_state, reward, terminated, truncated, info = env.step(action)\n",
    "        # 判断是否达到终止状态\n",
    "        done = terminated or truncated\n",
    "        \n",
    "        # 将这个五元组加到缓冲区中\n",
    "        agent.replay_buffer.add(state, action, reward, next_state, done)\n",
    "        # 累计奖励\n",
    "        episode_reward += reward\n",
    "\n",
    "        # 如果经验回放缓冲区已经有足够数据，就更新网络参数\n",
    "        if len(agent.replay_buffer) > batch_size:\n",
    "            agent.update(batch_size)\n",
    "        \n",
    "        # 更新当前状态\n",
    "        state = next_state\n",
    "\n",
    "        if done:\n",
    "            break\n",
    "    # 记录当前回合奖励值\n",
    "    episode_rewards.append(episode_reward)\n",
    "    # 打印中间值\n",
    "    if episode % 40 == 0:\n",
    "        tqdm.write(\"Episode \" + str(episode) + \": \" + str(episode_reward))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "442cc706",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 使用Matplotlib绘制奖励值的曲线图\n",
    "plt.plot(episode_rewards)\n",
    "plt.title(\"reward\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "f5ab5837",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 重置环境，开始新的一轮游戏\n",
    "observation, _ = env.reset()\n",
    "# 创建GymHelper对象来辅助显示\n",
    "gym_helper = GymHelper(env, figsize = (3, 3))\n",
    "\n",
    "# 开始游戏\n",
    "for i in range(500):\n",
    "    # 渲染环境，title为当前步骤数\n",
    "    gym_helper.render(title = str(i))\n",
    "    \n",
    "    # 通过Q网络找到当前状态下的最优动作\n",
    "    action = agent.choose_action(observation, 0)\n",
    "    # 执行action，获取新的信息\n",
    "    observation, reward, terminated, truncated, info = env.step(action)\n",
    "    \n",
    "    # 如果游戏结束，则结束当前循环\n",
    "    if terminated or truncated:\n",
    "        break\n",
    "\n",
    "# 游戏结束\n",
    "gym_helper.render(title = \"Finished\")\n",
    "# 关闭环境\n",
    "env.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b38694c3",
   "metadata": {},
   "source": [
    "### 3. Noisy DQN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "a33fb4bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "#定义带有高斯噪声的线性层\n",
    "class NoisyLinear(nn.Linear):\n",
    "    def __init__(self, in_features, out_features, sigma_zero=0.4, bias=True): \n",
    "        super(NoisyLinear, self).__init__(in_features, out_features, bias=bias)\n",
    "        # 初始化参数sigma_weight和sigma_bias\n",
    "        sigma_init = sigma_zero / math.sqrt(in_features)\n",
    "        self.sigma_weight = nn.Parameter(torch.Tensor(out_features, in_features).fill_(sigma_init))\n",
    "        self.register_buffer(\"epsilon_input\", torch.zeros(1, in_features))\n",
    "        self.register_buffer(\"epsilon_output\", torch.zeros(out_features, 1))\n",
    "        if bias:\n",
    "            self.sigma_bias = nn.Parameter(torch.Tensor(out_features).fill_(sigma_init))\n",
    "\n",
    "    def forward(self, input):\n",
    "        bias = self.bias\n",
    "        # 定义函数func，用于计算噪音项中的非线性函数\n",
    "        func = lambda x: torch.sign(x) * torch.sqrt(torch.abs(x))\n",
    "\n",
    "        with torch.no_grad():\n",
    "            # 生成服从标准正态分布的噪音项epsilon_input和epsilon_output\n",
    "            torch.randn(self.epsilon_input.size(), out=self.epsilon_input)\n",
    "            torch.randn(self.epsilon_output.size(), out=self.epsilon_output)\n",
    "            # 将噪音项通过非线性函数func进行处理，得到eps_in和eps_out\n",
    "            eps_in = func(self.epsilon_input)\n",
    "            eps_out = func(self.epsilon_output)\n",
    "            # 计算噪音项noise_v\n",
    "            noise_v = torch.mul(eps_in, eps_out).detach()\n",
    "        if bias is not None:\n",
    "            # 计算带有噪音的偏置项\n",
    "            bias = bias + self.sigma_bias * eps_out.t()\n",
    "        # 使用带有噪音的权重和偏置进行线性变换\n",
    "        return F.linear(input, self.weight + self.sigma_weight * noise_v, bias)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "59c4ab72",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义简单网络\n",
    "class Net(nn.Module):\n",
    "    def __init__(self, input_dim, output_dim):\n",
    "        super(Net, self).__init__()\n",
    "        self.input_dim = input_dim\n",
    "        self.output_dim = output_dim\n",
    "        \n",
    "        # 定义包含多个线性层和激活函数ReLU的网络\n",
    "        self.fc = nn.Sequential(\n",
    "            NoisyLinear(self.input_dim, 64), # 使用含有高斯噪声的线性层\n",
    "            nn.ReLU(),\n",
    "            NoisyLinear(64, 128), # 使用含有高斯噪声的线性层\n",
    "            nn.ReLU(),\n",
    "            NoisyLinear(128, self.output_dim) # 使用含有高斯噪声的线性层\n",
    "        )\n",
    "    \n",
    "    def forward(self, state):\n",
    "        # 前向传播，输出动作Q值\n",
    "        action_prob = self.fc(state)\n",
    "        return action_prob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "0d1e27c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 经验回放缓冲区\n",
    "class ReplayBuffer:\n",
    "    # 构造函数，max_size是缓冲区的最大容量\n",
    "    def __init__(self, max_size):\n",
    "        self.max_size = max_size\n",
    "        self.buffer = collections.deque(maxlen = self.max_size)  # 用collections的队列存储，先进先出\n",
    "\n",
    "    # 添加experience（五元组）到缓冲区\n",
    "    def add(self, state, action, reward, next_state, done):\n",
    "        experience = (state, action, reward, next_state, done)\n",
    "        self.buffer.append(experience)\n",
    "\n",
    "    # 从buffer中随机采样，数量为batch_size\n",
    "    def sample(self, batch_size):\n",
    "        batch = random.sample(self.buffer, batch_size)\n",
    "        state, action, reward, next_state, done = zip(*batch)\n",
    "        return state, action, reward, next_state, done\n",
    "    \n",
    "    # 返回缓冲区数据数量\n",
    "    def __len__(self):\n",
    "        return len(self.buffer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "ce5a1360",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义DQN类\n",
    "class Agent:\n",
    "    # 构造函数，参数包含环境，学习率，折扣因子，经验回放缓冲区大小，目标网络更新频率\n",
    "    def __init__(self, env, learning_rate=0.001, gamma=0.99, buffer_size=10000, T=10):\n",
    "        self.env = env\n",
    "        self.learning_rate = learning_rate\n",
    "        self.gamma = gamma\n",
    "        self.replay_buffer = ReplayBuffer(max_size=buffer_size)\n",
    "        self.T = T\n",
    "\n",
    "        # 判断可用的设备是 CPU 还是 GPU\n",
    "        self.device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "        # 定义Q网络和目标网络，模型结构是一样的\n",
    "        self.model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "        self.target_model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "\n",
    "        # 初始化时，令目标网络的参数就等于Q网络的参数\n",
    "        for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "            target_param.data.copy_(param)\n",
    "\n",
    "        # 定义Adam优化器\n",
    "        self.optimizer = torch.optim.Adam(self.model.parameters())\n",
    "        \n",
    "        # 记录模型更新的次数，用于决定何时更新目标模型\n",
    "        self.update_count = 0\n",
    "    \n",
    "    # 根据epsilon-greedy策略选择动作\n",
    "    def choose_action(self, state, epsilon=0.1):\n",
    "        if np.random.rand() < epsilon: # 以epsilon的概率随机选择一个动作\n",
    "            return np.random.randint(self.env.action_space.n)\n",
    "        else: # 否则选择模型认为最优的动作\n",
    "            state = torch.FloatTensor(np.array([state])).to(self.device)\n",
    "            action = self.model(state).argmax().item()\n",
    "            return action\n",
    "    \n",
    "    # 计算损失函数，参数batch为随机采样的一批数据\n",
    "    def compute_loss(self, batch):\n",
    "        # 取出数据，并将其转换为numpy数组\n",
    "        # 然后进一步转换为tensor，并将数据转移到指定计算资源设备上\n",
    "        states, actions, rewards, next_states, dones = batch\n",
    "        states = torch.FloatTensor(np.array(states)).to(self.device)\n",
    "        actions = torch.tensor(np.array(actions)).view(-1, 1).to(self.device)\n",
    "        rewards = torch.FloatTensor(np.array(rewards)).view(-1, 1).to(self.device)\n",
    "        next_states = torch.FloatTensor(np.array(next_states)).to(self.device)\n",
    "        dones = torch.FloatTensor(np.array(dones)).view(-1, 1).to(self.device)\n",
    "\n",
    "        # 计算当前Q值，即Q网络对当前状态动作样本对的Q值估计\n",
    "        curr_Q = self.model(states).gather(1, actions)\n",
    "        # 计算目标网络对下一状态的Q值估计\n",
    "        next_Q = self.target_model(next_states)\n",
    "        # 选择下一状态中最大的Q值\n",
    "        max_next_Q = torch.max(next_Q, 1)[0].view(-1, 1)\n",
    "        # 计算期望的Q值，若达到终止状态则直接是reward\n",
    "        expected_Q = rewards + (1 - dones) * self.gamma * max_next_Q\n",
    "        \n",
    "        # 计算当前Q值和期望Q值之间的均方误差，返回结果\n",
    "        loss = torch.mean(F.mse_loss(curr_Q, expected_Q))\n",
    "        return loss\n",
    "    \n",
    "    # 模型更新，参数为批次大小\n",
    "    def update(self, batch_size):\n",
    "        # 从经验回放缓冲区中随机采样\n",
    "        batch = self.replay_buffer.sample(batch_size)\n",
    "        # 计算这部分数据的损失\n",
    "        loss = self.compute_loss(batch)\n",
    "\n",
    "        # 梯度清零、反向传播、更新参数\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        self.optimizer.step()\n",
    "        \n",
    "        # 每隔一段时间，更新目标网络的参数\n",
    "        if self.update_count % self.T == 0:\n",
    "            for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "                target_param.data.copy_(param)\n",
    "        # 记录模型更新的次数\n",
    "        self.update_count += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "d5290d80",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Episode 0: 9.0                         \n",
      "Episode 40: 9.0                                 \n",
      "Episode 80: 234.0                               \n",
      "Episode 120: 137.0                               \n",
      "Episode 160: 295.0                               \n",
      "100%|██████████| 200/200 [01:55<00:00,  1.74it/s]\n"
     ]
    }
   ],
   "source": [
    "# 定义超参数\n",
    "max_episodes = 200 # 训练episode数\n",
    "max_steps = 500 # 每个回合的最大步数\n",
    "batch_size = 32 # 采样数\n",
    "\n",
    "# 创建DQN对象\n",
    "agent = Agent(env)\n",
    "# 定义保存每个回合奖励的列表\n",
    "episode_rewards = []\n",
    "\n",
    "# 开始循环，tqdm用于显示进度条并评估任务时间开销\n",
    "for episode in tqdm(range(max_episodes), file=sys.stdout):\n",
    "    # 重置环境并获取初始状态\n",
    "    state, _ = env.reset()\n",
    "    # 当前回合的奖励\n",
    "    episode_reward = 0\n",
    "\n",
    "    # 循环进行每一步操作\n",
    "    for step in range(max_steps):\n",
    "        # 根据当前状态选择动作\n",
    "        action = agent.choose_action(state)\n",
    "        # 执行动作，获取新的信息\n",
    "        next_state, reward, terminated, truncated, info = env.step(action)\n",
    "        # 判断是否达到终止状态\n",
    "        done = terminated or truncated\n",
    "        \n",
    "        # 将这个五元组加到缓冲区中\n",
    "        agent.replay_buffer.add(state, action, reward, next_state, done)\n",
    "        # 累计奖励\n",
    "        episode_reward += reward\n",
    "\n",
    "        # 如果经验回放缓冲区已经有足够数据，就更新网络参数\n",
    "        if len(agent.replay_buffer) > batch_size:\n",
    "            agent.update(batch_size)\n",
    "        \n",
    "        # 更新当前状态\n",
    "        state = next_state\n",
    "\n",
    "        if done:\n",
    "            break\n",
    "    # 记录当前回合奖励值\n",
    "    episode_rewards.append(episode_reward)\n",
    "    # 打印中间值\n",
    "    if episode % 40 == 0:\n",
    "        tqdm.write(\"Episode \" + str(episode) + \": \" + str(episode_reward))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "70c68964",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 使用Matplotlib绘制奖励值的曲线图\n",
    "plt.plot(episode_rewards)\n",
    "plt.title(\"reward\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "14cbbab0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 重置环境，开始新的一轮游戏\n",
    "observation, _ = env.reset()\n",
    "# 创建GymHelper对象来辅助显示\n",
    "gym_helper = GymHelper(env, figsize = (3, 3))\n",
    "\n",
    "# 开始游戏\n",
    "for i in range(500):\n",
    "    # 渲染环境，title为当前步骤数\n",
    "    gym_helper.render(title = str(i))\n",
    "    \n",
    "    # 通过Q网络找到当前状态下的最优动作\n",
    "    action = agent.choose_action(observation, 0)\n",
    "    # 执行action，获取新的信息\n",
    "    observation, reward, terminated, truncated, info = env.step(action)\n",
    "    \n",
    "    # 如果游戏结束，则结束当前循环\n",
    "    if terminated or truncated:\n",
    "        break\n",
    "\n",
    "# 游戏结束\n",
    "gym_helper.render(title = \"Finished\")\n",
    "# 关闭环境\n",
    "env.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "802f9b9b",
   "metadata": {},
   "source": [
    "### 4. Prioritized Experience Replay"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "fed275fd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义简单神经网络\n",
    "class Net(nn.Module):\n",
    "    def __init__(self, input_dim, output_dim):\n",
    "        super(Net, self).__init__()\n",
    "        self.input_dim = input_dim # 网络的输入维度\n",
    "        self.output_dim = output_dim # 网络的输出维度\n",
    "        \n",
    "        # 定义一个仅包含全连接层的网络，激活函数使用ReLU函数\n",
    "        self.fc = nn.Sequential(\n",
    "            nn.Linear(self.input_dim, 64),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(64, 128),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, self.output_dim)\n",
    "        )\n",
    "    \n",
    "    # 定义前向传播，输出动作Q值\n",
    "    def forward(self, state):\n",
    "        action_prob = self.fc(state)\n",
    "        return action_prob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "21eb5db8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "class BinaryTree:\n",
    "    # 二叉树结构，目的是降低一些操作的复杂度到O(log(n))\n",
    "    def __init__(self, capacity):\n",
    "        #初始化BinaryTree对象\n",
    "        self.capacity = capacity # BinaryTree的容量\n",
    "        self.tree = np.zeros(2 * capacity - 1)  # 存储BinaryTree结构的数组\n",
    "        self.data = np.zeros(capacity, dtype=object)  # 存储数据的数组\n",
    "        self.n_entries = 0  # 当前存储的数据数量\n",
    "\n",
    "    def _propagate(self, idx, change): # idx: 当前节点的索引； change: 更新的变化值\n",
    "        # 更新根节点的值\n",
    "        parent = (idx - 1) // 2  # 计算当前节点的父节点索引\n",
    "        self.tree[parent] += change  # 更新父节点的值\n",
    "        if parent != 0:\n",
    "            self._propagate(parent, change)  # 递归更新父节点的父节点\n",
    "\n",
    "    def _retrieve(self, idx, s): # idx: 当前节点的索引； s: 要查找的值\n",
    "        # 根据给定的值在叶子节点中查找样本\n",
    "        left = 2 * idx + 1  # 计算左子节点的索引\n",
    "        right = left + 1  # 计算右子节点的索引\n",
    "\n",
    "        if left >= len(self.tree):\n",
    "            return idx  # 达到叶子节点返回当前节点的索引\n",
    "\n",
    "        if s <= self.tree[left]:\n",
    "            return self._retrieve(left, s)  # 在左子树中查找样本\n",
    "        else:\n",
    "            return self._retrieve(right, s - self.tree[left])  # 在右子树中查找样本，返回样本的索引\n",
    "\n",
    "    def total(self):\n",
    "        # 获取BinaryTree的总和\n",
    "        return self.tree[0]\n",
    "\n",
    "    def add(self, data， priority): # data: 要添加的数据, priority: 样本的优先级\n",
    "        # 添加优先级和数据\n",
    "        idx = self.n_entries + self.capacity - 1  # 计算数据在tree数组中的索引\n",
    "\n",
    "        self.data[self.n_entries] = data  # 存储数据\n",
    "        self.update(idx, priority)  # 更新优先级\n",
    "\n",
    "        self.n_entries += 1  # 增加存储的数据数量\n",
    "        if self.n_entries >= self.capacity:\n",
    "            self.n_entries = 0\n",
    "\n",
    "    def update(self, idx, priority): # idx: 要更新的节点的索引； priority: 新的优先级\n",
    "        # 更新指定索引位置的优先级\n",
    "        change = priority - self.tree[idx]  # 计算优先级的变化值\n",
    "\n",
    "        self.tree[idx] = priority  # 更新优先级\n",
    "        self._propagate(idx, change)  # 更新父节点的值\n",
    "\n",
    "    def get(self, s):  # s: 要获取的值\n",
    "        # 根据给定的值获取对应的优先级和数据\n",
    "        idx = self._retrieve(0, s)  # 在叶子节点中查找样本的索引\n",
    "        data_idx = idx - self.capacity + 1  # 计算数据在data数组中的索引\n",
    "\n",
    "        return (idx, self.tree[idx], self.data[data_idx])  # 返回节点索引、优先级和数据的元组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "87bc0a08",
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReplayBuffer:\n",
    "    def __init__(self, max_size=1000, alpha=0.6, epsilon=0.01):\n",
    "        # 初始化ReplayBuffer对象 \n",
    "        # max_size: ReplayBuffer的最大容量; alpha: 优先级的权重因子; epsilon: 优先级的平滑项\n",
    "        self.tree = BinaryTree(max_size)  # 使用BinaryTree作为存储结构\n",
    "        self.max_size = max_size\n",
    "        self.prio_max = 0.1  # 优先级的最大值\n",
    "        self.alpha = alpha\n",
    "        self.epsilon = epsilon\n",
    "        \n",
    "    def add(self, state, action, reward, next_state, done):\n",
    "        # 添加经验数据\n",
    "        data = (state, action, reward, next_state, done)  # 组装数据元组\n",
    "        priority = (np.abs(self.prio_max) + self.epsilon) ** self.alpha  # 计算优先级\n",
    "        self.tree.add(data, priority)  # 添加到BinaryTree中\n",
    "\n",
    "    def sample(self, batch_size):\n",
    "        # 从ReplayBuffer中采样一批数据\n",
    "        states, actions, rewards, next_states, dones = [], [], [], [], []\n",
    "        idxs = []\n",
    "        segment = self.tree.total() / batch_size  # 计算每个样本所在的区间大小\n",
    "        priorities = []\n",
    "\n",
    "        for i in range(batch_size):\n",
    "            a = segment * i\n",
    "            b = segment * (i + 1)\n",
    "            s = random.uniform(a, b)  # 在区间内随机选择一个值\n",
    "            idx, priority, data = self.tree.get(s)  # 根据值获取样本和优先级\n",
    "\n",
    "            state, action, reward, next_state, done = data\n",
    "            states.append(state)\n",
    "            actions.append(action)\n",
    "            rewards.append(reward)\n",
    "            next_states.append(next_state)\n",
    "            dones.append(done)\n",
    "            priorities.append(priority)\n",
    "            \n",
    "        return states, actions, rewards, next_states, dones #  包含批次数据的元组 (状态列表, 动作列表, 奖励列表, 下一个状态列表, 是否终止列表)\n",
    "    \n",
    "    def update(self, idxs, errors):\n",
    "        # 更新样本的优先级\n",
    "        # idxs: 要更新优先级的样本的索引列表 ; errors: 对应样本的误差列表\n",
    "        self.prio_max = max(self.prio_max, max(np.abs(errors)))  # 更新优先级的最大值\n",
    "        for i, idx in enumerate(idxs):\n",
    "            priority = (np.abs(errors[i]) + self.epsilon) ** self.alpha  # 计算优先级\n",
    "            self.tree.update(idx, priority)  # 更新优先级\n",
    "        \n",
    "    def __len__(self):\n",
    "        # 获取ReplayBuffer中存储的数据数量\n",
    "        return self.tree.n_entries\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "d8ba1d29",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义DQN类\n",
    "class DQN:\n",
    "    # 构造函数，参数包含环境，学习率，折扣因子，经验回放缓冲区大小，目标网络更新频率\n",
    "    def __init__(self, env, learning_rate=0.001, gamma=0.99, buffer_size=10000, T=10):\n",
    "        self.env = env\n",
    "        self.learning_rate = learning_rate\n",
    "        self.gamma = gamma\n",
    "        self.replay_buffer = ReplayBuffer(max_size=buffer_size)\n",
    "        self.T = T\n",
    "\n",
    "        # 判断可用的设备是 CPU 还是 GPU\n",
    "        self.device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "        # 定义Q网络和目标网络，模型结构是一样的\n",
    "        self.model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "        self.target_model = Net(env.observation_space.shape[0], env.action_space.n).to(self.device)\n",
    "\n",
    "        # 初始化时，令目标网络的参数就等于Q网络的参数\n",
    "        for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "            target_param.data.copy_(param)\n",
    "\n",
    "        # 定义Adam优化器\n",
    "        self.optimizer = torch.optim.Adam(self.model.parameters())\n",
    "        \n",
    "        # 记录模型更新的次数，用于决定何时更新目标模型\n",
    "        self.update_count = 0\n",
    "    \n",
    "    # 根据epsilon-greedy策略选择动作\n",
    "    def choose_action(self, state, epsilon=0.1):\n",
    "        if np.random.rand() < epsilon: # 以epsilon的概率随机选择一个动作\n",
    "            return np.random.randint(self.env.action_space.n)\n",
    "        else: # 否则选择模型认为最优的动作\n",
    "            state = torch.FloatTensor(np.array([state])).to(self.device)\n",
    "            action = self.model(state).argmax().item()\n",
    "            return action\n",
    "    \n",
    "    # 计算损失函数，参数batch为随机采样的一批数据\n",
    "    def compute_loss(self, batch):\n",
    "        # 取出数据，并将其转换为numpy数组\n",
    "        # 然后进一步转换为tensor，并将数据转移到指定计算资源设备上\n",
    "        states, actions, rewards, next_states, dones = batch\n",
    "        states = torch.FloatTensor(np.array(states)).to(self.device)\n",
    "        actions = torch.tensor(np.array(actions)).view(-1, 1).to(self.device)\n",
    "        rewards = torch.FloatTensor(np.array(rewards)).view(-1, 1).to(self.device)\n",
    "        next_states = torch.FloatTensor(np.array(next_states)).to(self.device)\n",
    "        dones = torch.FloatTensor(np.array(dones)).view(-1, 1).to(self.device)\n",
    "\n",
    "        # 计算当前Q值，即Q网络对当前状态动作样本对的Q值估计\n",
    "        curr_Q = self.model(states).gather(1, actions)\n",
    "        # 计算目标网络对下一状态的Q值估计\n",
    "        next_Q = self.target_model(next_states)\n",
    "        # 选择下一状态中最大的Q值\n",
    "        max_next_Q = torch.max(next_Q, 1)[0].view(-1, 1)\n",
    "        # 计算期望的Q值，若达到终止状态则直接是reward\n",
    "        expected_Q = rewards + (1 - dones) * self.gamma * max_next_Q\n",
    "        \n",
    "        # 计算当前Q值和期望Q值之间的均方误差，返回结果\n",
    "        loss = torch.mean(F.mse_loss(curr_Q, expected_Q))\n",
    "        return loss\n",
    "    \n",
    "    # 模型更新，参数为批次大小\n",
    "    def update(self, batch_size):\n",
    "        # 从经验回放缓冲区中随机采样\n",
    "        batch = self.replay_buffer.sample(batch_size)\n",
    "        # 计算这部分数据的损失\n",
    "        loss = self.compute_loss(batch)\n",
    "\n",
    "        # 梯度清零、反向传播、更新参数\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        self.optimizer.step()\n",
    "        \n",
    "        # 每隔一段时间，更新目标网络的参数\n",
    "        if self.update_count % self.T == 0:\n",
    "            for param, target_param in zip(self.model.parameters(), self.target_model.parameters()):\n",
    "                target_param.data.copy_(param)\n",
    "        # 记录模型更新的次数\n",
    "        self.update_count += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "ae992869",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Episode 0: 9.0                         \n",
      "Episode 40: 249.0                               \n",
      "Episode 80: 9.0                                 \n",
      "Episode 120: 500.0                               \n",
      "Episode 160: 500.0                               \n",
      "100%|██████████| 200/200 [01:29<00:00,  2.23it/s]\n"
     ]
    }
   ],
   "source": [
    "# 定义超参数\n",
    "max_episodes = 200 # 训练episode数\n",
    "max_steps = 500 # 每个回合的最大步数\n",
    "batch_size = 32 # 采样数\n",
    "\n",
    "# 创建DQN对象\n",
    "agent = DQN(env)\n",
    "# 定义保存每个回合奖励的列表\n",
    "episode_rewards = []\n",
    "\n",
    "# 开始循环，tqdm用于显示进度条并评估任务时间开销\n",
    "for episode in tqdm(range(max_episodes), file=sys.stdout):\n",
    "    # 重置环境并获取初始状态\n",
    "    state, _ = env.reset()\n",
    "    # 当前回合的奖励\n",
    "    episode_reward = 0\n",
    "\n",
    "    # 循环进行每一步操作\n",
    "    for step in range(max_steps):\n",
    "        # 根据当前状态选择动作\n",
    "        action = agent.choose_action(state)\n",
    "        # 执行动作，获取新的信息\n",
    "        next_state, reward, terminated, truncated, info = env.step(action)\n",
    "        # 判断是否达到终止状态\n",
    "        done = terminated or truncated\n",
    "        \n",
    "        # 将这个五元组加到缓冲区中\n",
    "        agent.replay_buffer.add(state, action, reward, next_state, done)\n",
    "        # 累计奖励\n",
    "        episode_reward += reward\n",
    "\n",
    "        # 如果经验回放缓冲区已经有足够数据，就更新网络参数\n",
    "        if len(agent.replay_buffer) > batch_size:\n",
    "            agent.update(batch_size)\n",
    "        \n",
    "        # 更新当前状态\n",
    "        state = next_state\n",
    "\n",
    "        if done:\n",
    "            break\n",
    "    # 记录当前回合奖励值\n",
    "    episode_rewards.append(episode_reward)\n",
    "    # 打印中间值\n",
    "    if episode % 40 == 0:\n",
    "        tqdm.write(\"Episode \" + str(episode) + \": \" + str(episode_reward))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "b5a70a33",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 使用Matplotlib绘制奖励值的曲线图\n",
    "plt.plot(episode_rewards)\n",
    "plt.title(\"reward\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "32678c45",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 重置环境，开始新的一轮游戏\n",
    "observation, _ = env.reset()\n",
    "# 创建GymHelper对象来辅助显示\n",
    "gym_helper = GymHelper(env, figsize = (3, 3))\n",
    "\n",
    "# 开始游戏\n",
    "for i in range(1000):\n",
    "    # 渲染环境，title为当前步骤数\n",
    "    gym_helper.render(title = str(i))\n",
    "    \n",
    "    # 通过Q网络找到当前状态下的最优动作\n",
    "    action = agent.choose_action(observation, 0)\n",
    "    # 执行action，获取新的信息\n",
    "    observation, reward, terminated, truncated, info = env.step(action)\n",
    "    \n",
    "    # 如果游戏结束，则结束当前循环\n",
    "    if terminated or truncated:\n",
    "        break\n",
    "\n",
    "# 游戏结束\n",
    "gym_helper.render(title = \"Finished\")\n",
    "# 关闭环境\n",
    "env.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "989f4c56",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
